package gu.sql2java.json;

import static com.google.common.base.Preconditions.checkNotNull;
import static gu.sql2java.transformer.ColumnTransformer.INTERGRAL_CLASSES;
import static com.google.common.base.Preconditions.checkArgument;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Set;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.serializer.CollectionCodec;
import com.alibaba.fastjson.serializer.IntegerCodec;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.LongCodec;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.google.common.base.Function;

/**
 * 整数(Long|Integer)转(枚举)字符串集合的序列化和反序列化实现
 * @author guyadong
 * @since 3.27.0
 */
public class IntegralbitsFastjsonCodec<T> implements ObjectSerializer, ObjectDeserializer{
	private final Class<T> type;
	@SuppressWarnings("rawtypes")
	private final Function<Collection, T> agg;
	private final Function<T, Set<String>> split;
	/**
	 * @param type 数字类型(Long|Integer|Short|Byte)
	 * @param agg 将字符串集合聚合为整数的函数
	 * @param split 将整数拆分为字符串集合的函数
	 */
	@SuppressWarnings("rawtypes")
	public IntegralbitsFastjsonCodec (Class<T>type,
			Function<Collection, T> agg,
			Function< T,Set<String>> split) {
		this.type = checkNotNull(type,"type is null");
		checkArgument(INTERGRAL_CLASSES.contains(type),
				"Long , Integer, Short or Byte type required");
		this.agg = checkNotNull(agg,"agg is null");
		this.split = checkNotNull(split,"split is null");
	}

    @SuppressWarnings({ "unchecked" })
	@Override
	public T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        final int token = parser.lexer.token();
		if (token == JSONToken.LBRACKET) {
			Set<String> s = CollectionCodec.instance.deserialze(parser, new TypeReference<Set<String>>() {}.getType(), fieldName);
			return this.type.cast( agg.apply(s));
		}else if (Integer.class.equals(this.type)){
			return IntegerCodec.instance.deserialze(parser, type, fieldName);
		}else if (Long.class.equals(this.type)){
			return LongCodec.instance.deserialze(parser, type, fieldName);
		}else if (Short.class.equals(this.type)) {
			return (T)(Short)((Integer)IntegerCodec.instance.deserialze(parser, type, fieldName)).shortValue();
		}else {
			return (T)(Byte)((Integer)IntegerCodec.instance.deserialze(parser, type, fieldName)).byteValue();
		}
	}

	@Override
	public int getFastMatchToken() {
		return JSONToken.LBRACKET;
	}

	@Override
	public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features)
			throws IOException {
		 if (null==object || !INTERGRAL_CLASSES.contains(object.getClass())) {
			 LongCodec.instance.write(serializer, object, fieldName, fieldType, features);
		 }
		Set<String> s = split.apply(this.type.cast(object));
		CollectionCodec.instance.write(serializer, s, fieldName, fieldType, features);
	}

}
